
/* Generated by Interface Builder */

#import "Instrum.h"
#import <objc/List.h>
#import <appkit/Form.h>
#import <appkit/Panel.h>
#import <objc/Storage.h>
#import "UnitGen.h"
#import "Oscil.h"
#import "Out.h"
#import "Statement.h"

@implementation Instrum

- init
{
	ugenList = [[List alloc] initCount:5];
	varList = [[List alloc] initCount:10];
	assignList = [[List alloc] initCount:10];
	loopList = [[List alloc] initCount:10];
	endList = [[List alloc] initCount:5];
	
	setline = inputSound = NO;
	
	return self;
}

- printUgenLocs		// displays unit generator locations, for debugging
{
	id ugen;
	int i;
	unsigned int c;
	
	c = [ugenList count];
	for(i = 0; i < [ugenList count]; i++) {
		ugen = [ugenList objectAt:i];
		[ugen show];
	}
	return self;
}

- findUgenAtPoint:(NXPoint *)point		// find the unit generator at PatchView location
{
	id 		ugen;
	int 	i;
	NXRect  *rect;
	
	// get the ugen 
	for(i = 0; i < [ugenList count]; i++) {
		ugen = [ugenList objectAt:i];
		rect = [ugen getRect];
		if(NXMouseInRect(point,rect,NO)) {
			return ugen;
		}
	}
	return nil;
}

- putUgenInList:ugen		// store a new unit generator
{
	unsigned int n;

	n = [ugenList count];
	[ugen setIndex:n];
	[ugenList addObject:ugen];
	return self;
}

- removeUgenFromList:ugen		// delete a unit generator
{
	unsigned int n;
	unsigned int c;
	int i;

	n = [ugen getIndex];
	c = [ugenList count];
	[ugenList removeObject:ugen];
	for(i = n; i < c; i++)
		[[ugenList objectAt:n] setIndex:n];
	
	return self;
}

- putVarInList:(char *)var		// store a variable used by a unit generator 
{
	id statement;
	
	statement = [Statement alloc];
	[statement storeString:var];
	[varList addObject:statement];
	return self;
}

- putAssignInList:(char *)assign	// store an assignment statement used by a unit generator
{
	id statement;
	
	statement = [Statement alloc];
	[statement storeString:assign];
	[assignList addObject:statement];
	return self;
}

- putLoopInList:(char *)loop		//  store a statement occurring within sample loop
							//  used by a unit generator
{
	id statement;
	
	statement = [Statement alloc];
	[statement storeString:loop];
	[loopList addObject:statement];
	return self;
}

- putEndInList:(char *)end		//  store a statement occurring within sample loop
							//  used by a unit generator
{
	id statement;
	
	statement = [Statement alloc];
	[statement storeString:end];
	[endList addObject:statement];
	return self;
}

- writeCodeWithName:(char *)instName andDir:(char *)instDir andCmd:(char *)cmdDir andCmix:(char *)cmixDir
							// write out the instrument code
{
	id outUgen;
	int i;
	
	strcpy(name,instName);
	strcpy(directory,instDir);
	sprintf(file,"%s/%s.c",directory,name);

	outUgen = [ugenList objectAt:0];
	
	for(i = 0; i < [ugenList count]; i++) 
		[[ugenList objectAt:i] newWrite];	// set all ugens as not written
	
	[self freeCodeLists]; 		// removed old code
						    	// recursively writes all the code for each ugen
	[outUgen writeUgen];		// from out, travels up tree and then down, 
							// writing code for each ugen as finished

	if (![self head:cmixDir])
		return self;
	[self body];
	[self tail];
	[self profile:cmixDir];
	[self makeWithCmd:cmdDir andCmix:cmixDir];
    return self;
}

- head:(char *)cmixDir			// writes out include statements, etc. of cmix instrument
{
	fp = fopen(file,"w");
	if(!fp) {
		NXRunAlertPanel("patchmix","This file can't be opened. Check out the directory. %s","OK",NULL,NULL,file);
		return 0;
	}
							// variables & includes for all instr:	
	fprintf(fp, "#include \"%s/H/ugens.h\"\n",cmixDir);
 	fprintf(fp, "#include \"%s/H/sfheader.h\"\n",cmixDir);
 	fprintf(fp, "#include \"%s/macros/macros.h\"\n",cmixDir);
 	fprintf(fp, "#include <stdio.h>\n#include <sys/file.h>\n");
	fprintf(fp, "#include <sys/types.h>\n\n");
       	fprintf(fp, "extern SFHEADER      sfdesc[NFILES];\n\n");
	fprintf(fp, "%s(p,n_args)\n\n", name);
	fprintf(fp, "float *p; /* array of p-fields */\n");
	fprintf(fp, "int n_args; /* number of p-fields */\n\n{\n");

	fprintf(fp, "\tint chans;\n");
	fprintf(fp, "\tlong nsamps,i;\n");
	fclose(fp);
	return self;
}

- body			// writes body of cmix instrument, from the 3 lists of 
				// variable declarations, assignment statements and 
				// statements occurring within the sample loop
{
	int i;
	char *str;	

	fp = fopen(file,"a");
	if(!fp) {
		NXRunAlertPanel("patchmix","This file can't be opened. Check out the directory. %s","OK",NULL,NULL,file);
		return 0;
	}
	fprintf(fp, "\tfloat amp;\n");
	fprintf(fp, "\tfloat out[2];\n");

	for(i = 0; i < [varList count]; i++) {
		str = [[varList objectAt:i] getString];
		fprintf(fp,"%s",str);
	}
	fprintf(fp, "\tnsamps = setnote(p[0],p[1],0);\n"); 
	fprintf(fp, "\tchans = sfchans(&sfdesc[0]);\n");

// initial assignment statements
	for(i = 0; i < [assignList count]; i++) {
		str = [[assignList objectAt:i] getString];
		fprintf(fp,"%s",str);
	}

//  sample loop statements (signal processing)
	fprintf(fp, "\tfor(i = 0; i < nsamps; i++) {\n");
	for(i = 0; i < [loopList count]; i++) {
		str = [[loopList objectAt:i] getString];
		fprintf(fp,"%s",str);
	}
	
	fclose(fp);
	return self;
}

- tail			// end of instrument code 
{
	int i;
	char *str;	
	
	fp = fopen(file,"a");
	if(!fp) {
		NXRunAlertPanel("patchmix","This file can't be opened. Check out the directory. %s","OK",NULL,NULL,file);
		return 0;
	}
	fprintf(fp, "\t\tADDOUT(out,0);\n\t}\n");

	fprintf(fp, "\tendnote(0);\n");

	for(i = 0; i < [endList count]; i++) {
		str = [[endList objectAt:i] getString];
		fprintf(fp,"%s",str);
	}

	fprintf(fp, "}\n");

	fclose(fp);
	return self;
}

- profile:(char *)cmixDir		// writes cmix "profile.c", which introduces your instrument
						// into the list of cmix functions when compiled with cmix objects
{
	char profile[80];

	sprintf(profile,"%s/profile.c",directory);
	fp = fopen(profile,"w");
	if(!fp) {
		NXRunAlertPanel("patchmix","This file can't be opened. Check out the directory. %s","OK",NULL,NULL,profile);
		return 0;
	}

	fprintf(fp,"#include \"%s/H/ugens.h\"\n",cmixDir);
	fprintf(fp,"int FSPACE = 1;\n");
	fprintf(fp,"int NBYTES = 32768;\n\n");
	fprintf(fp,"profile()\n{\n");
	fprintf(fp,"\tUG_INTRO(\"%s\",%s);\n}\n",name,name);
	fclose(fp);
	return self;
}

- makeWithCmd:(char *)cmdDir andCmix:(char *)cmixDir     // writes out makefile 
{
	char makefile[80];
	
	sprintf(makefile,"%s/Makefile",directory);
	fp = fopen(makefile,"w");
	if(!fp) {
		NXRunAlertPanel("patchmix","This file can't be opened. Check out the directory. %s","OK",NULL,NULL,makefile);
		return 0;
	}

	fprintf(fp,"CFLAGS =  -O\n");
	fprintf(fp,"POBJECTS = %s.o profile.o\n",name);
	fprintf(fp,"LDFLAGS =  %s/cmix.o %s/lib/genlib.a -lm\n\n",cmdDir,cmixDir);
	fprintf(fp,"%s:  %s/H/ugens.h $(POBJECTS) %s/cmix.o\n", name,cmixDir, cmdDir);
	fprintf(fp,"\tcc -o %s $(POBJECTS) $(LDFLAGS)\n",name);
	fclose(fp);	
	return self;
}


- freeUgens
{
	[ugenList freeObjects];
	[ugenList empty];
	[self freeCodeLists];
	return self;
}

- freeCodeLists
{
	[varList freeObjects];
	[varList empty];
	[assignList freeObjects];
	[assignList empty];
	[loopList freeObjects];
	[loopList empty];
	[endList freeObjects];
	[endList empty];
	return self;
}

@end
